//Copyright 2010 Balazs Keri, Imre Keri
//
//This file is part of FireworksCreator.
//
//FireworksCreator is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//FireworksCreator is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with FireworksCreator.  If not, see <http://www.gnu.org/licenses/>.
//
#include <QBoxLayout>
#include <QCheckBox>
#include <QComboBox>
#include <QDoubleValidator>
#include <QFileDialog>
#include <QLineEdit>
#include <QLocale>
#include <QPushButton>
#include <QSpinBox>
#include <QToolButton>
#include "modeldataobjectadapter.h"
#include "primitives.h"
#include "primitivegroup.h"
#include "randomdoublewidget.h"
#include "ptgenericview.h"
//
PTGenericView::PTGenericView(QObject *p_parent)
:
   QObject(p_parent),
   visible_check(new QPushButton()),
   life_time_widget(new RandomDoubleWidget()),
   density_edit(new QLineEdit()),
   gravitation_check(new QCheckBox()),
   friction_check(new QCheckBox()),
   shape_combo(new QComboBox()),
   texture_edit(new QLineEdit()),
   texture_browse_button(new QToolButton()),
   texture_widget(new QWidget()),
   tile_s_spin(new QSpinBox()),
   tile_t_spin(new QSpinBox()),
   num_tiles_edit(new QLineEdit()),
   tile_speed_mode_combo(new QComboBox())
{
   visible_check->setCheckable(true);
   life_time_widget->show();
   density_edit->setValidator(new QDoubleValidator(1.0/16,65536.0,4,this));
   //
   shape_combo->setEditable(false);
   shape_combo->addItem(QIcon(),tr("point","particletemplate_shape"),model::ParticleTemplate::shape_point);
   shape_combo->addItem(QIcon(),tr("quad","particletemplate_shape"),model::ParticleTemplate::shape_quad);
   shape_combo->addItem(QIcon(),tr("quad_trianglestrip","particletemplate_shape"),model::ParticleTemplate::shape_quad_trianglestrip);
   shape_combo->addItem(QIcon(),tr("hexagon","particletemplate_shape"),model::ParticleTemplate::shape_hexagon);
   //
   QLayout *l=new QHBoxLayout();
   l->setSpacing(0);
   l->setMargin(0);
   l->addWidget(texture_edit);
   l->addWidget(texture_browse_button);
   texture_widget->setLayout(l);
   //
   tile_s_spin->setRange(1,32767);
   tile_t_spin->setRange(1,32767);
   //
   num_tiles_edit->setValidator(new QDoubleValidator(1.0/16,65536.0,4,this));
   //
   tile_speed_mode_combo->setEditable(false);
   tile_speed_mode_combo->addItem(QIcon(),tr("relative","particletemplate_tile_speed_mode"),model::ParticleTemplate::tile_speed_relative);
   tile_speed_mode_combo->addItem(QIcon(),tr("absolute","particletemplate_tile_speed_mode"),model::ParticleTemplate::tile_speed_absolute);
   //
   connect(visible_check,SIGNAL(clicked()),SLOT(on_visible_check_clicked()));
   connect(life_time_widget,SIGNAL(value_changed()),SLOT(on_life_time_value_changed()));
   connect(density_edit,SIGNAL(editingFinished()),SLOT(on_density_edit_editing_finished()));
   connect(gravitation_check,SIGNAL(clicked()),SLOT(on_gravitation_check_clicked()));
   connect(friction_check,SIGNAL(clicked()),SLOT(on_friction_check_clicked()));
   connect(shape_combo,SIGNAL(currentIndexChanged(int)),SLOT(on_shape_combo_current_index_changed(int)));
   connect(texture_edit,SIGNAL(editingFinished()),SLOT(on_texture_edit_editing_finished()));
   connect(texture_browse_button,SIGNAL(clicked()),SLOT(on_texture_browse_button_clicked()));
   connect(tile_s_spin,SIGNAL(valueChanged(int)),SLOT(on_tile_s_value_changed(int)));
   connect(tile_t_spin,SIGNAL(valueChanged(int)),SLOT(on_tile_t_value_changed(int)));
   connect(num_tiles_edit,SIGNAL(editingFinished()),SLOT(on_num_tiles_edit_editing_finished()));
   connect(tile_speed_mode_combo,SIGNAL(currentIndexChanged(int)),SLOT(on_tile_speed_mode_combo_current_index_changed(int)));
}
PTGenericView::~PTGenericView()
{
}
//
void PTGenericView::on_visible_check_clicked()
{
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change visibility of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTVisible(visible_check->isChecked())));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
void PTGenericView::on_life_time_value_changed()
{
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change lifetime of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTLifeTime(life_time_widget->get_value())));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
void PTGenericView::on_density_edit_editing_finished()
{
   if(!density_edit->isModified())
   {
      return;
   }
   //
   float const new_density=QLocale::system().toFloat(density_edit->text());
   /*if(get_object()->get_density()==new_density)
   {
      return;
   }*/
   //
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change density of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTDensity(new_density)));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
void PTGenericView::on_gravitation_check_clicked()
{
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change gravitation enabled of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTGravitationEnabled(gravitation_check->isChecked())));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
void PTGenericView::on_friction_check_clicked()
{
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change friction enabled of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTFrictionEnabled(friction_check->isChecked())));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
void PTGenericView::on_shape_combo_current_index_changed(int p_i)
{
   QVariant data(shape_combo->itemData(p_i));
   if(!data.isValid())
      return;
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change shape of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTShape(model::ParticleTemplate::Shape(data.toInt()))));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
void PTGenericView::on_texture_edit_editing_finished()
{
   if(!texture_edit->isModified())
   {
      return;
   }
   update_pt_texture_file(texture_edit->text());
}

void PTGenericView::on_texture_browse_button_clicked()
{
   QFileDialog fd(0,Qt::Dialog);
   fd.setFileMode(QFileDialog::AnyFile);
   fd.setNameFilter(tr("Image files (*.png;???)"));
   fd.setViewMode(QFileDialog::List);
   fd.setWindowTitle(tr("Select texture image"));
   fd.setLabelText(QFileDialog::Accept, tr("Select"));
   if (!fd.exec())
      return;
   QFileInfo fi(fd.selectedFiles().at(0));
   QString file_name(fi.absoluteFilePath());
   update_pt_texture_file(file_name);
}
void PTGenericView::on_tile_s_value_changed(int p_value)
{
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change tiles X of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTTileS(p_value)));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
void PTGenericView::on_tile_t_value_changed(int p_value)
{
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change tiles Y of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTTileT(p_value)));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
void PTGenericView::on_num_tiles_edit_editing_finished()
{
   if(!num_tiles_edit->isModified())
   {
      return;
   }
   //
   float const new_value=QLocale::system().toFloat(num_tiles_edit->text());
   /*if(get_object()->get_num_tiles()==new_value)
   {
      return;
   }*/
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change tile count of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTNumTiles(new_value)));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
void PTGenericView::on_tile_speed_mode_combo_current_index_changed(int p_i)
{
   QVariant data(tile_speed_mode_combo->itemData(p_i));
   if(!data.isValid())
      return;
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change texture animation mode of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTTileSpeedMode(model::ParticleTemplate::TileSpeedMode(data.toInt()))));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
//
void PTGenericView::handle_object_changed(model::ParticleTemplate *old_object)
{
   bool const e=(get_object()!=0);
   block_edit_signals(true);
   visible_check->setEnabled(e);
   density_edit->setEnabled(e);
   gravitation_check->setEnabled(e);
   friction_check->setEnabled(e);
   shape_combo->setEnabled(e);
   texture_edit->setEnabled(e);
   texture_browse_button->setEnabled(e);
   tile_s_spin->setEnabled(e);
   tile_t_spin->setEnabled(e);
   num_tiles_edit->setEnabled(e);
   tile_speed_mode_combo->setEnabled(e);
   if(get_object())
   {
      visible_check->setChecked(get_object()->get_visible());
      life_time_widget->set_value(get_object()->get_life_time());
      density_edit->setText(QLocale::system().toString(get_object()->get_density()));
      gravitation_check->setChecked(get_object()->get_gravitation_enabled());
      friction_check->setChecked(get_object()->get_friction_enabled());
      shape_combo->setCurrentIndex(shape_combo->findData(get_object()->get_shape()));
      texture_edit->setText(get_object()->get_texture_file());
      tile_s_spin->setValue(get_object()->get_tile_s());
      tile_t_spin->setValue(get_object()->get_tile_t());
      num_tiles_edit->setText(QLocale::system().toString(get_object()->get_num_tiles()));
      tile_speed_mode_combo->setCurrentIndex(tile_speed_mode_combo->findData(get_object()->get_tile_speed_mode()));
   }
   else
   {
      visible_check->setChecked(false);
      life_time_widget->set_null_value(true);
      density_edit->clear();
      gravitation_check->setChecked(false);
      friction_check->setChecked(false);
      shape_combo->setCurrentIndex(-1);
      texture_edit->clear();
      tile_s_spin->clear();
      tile_t_spin->clear();
      num_tiles_edit->clear();
      tile_speed_mode_combo->setCurrentIndex(-1);
   }
   block_edit_signals(false);
}
void PTGenericView::handle_post_primitive(const Primitive &prim)
{
   using namespace Primitives;
   switch(prim.type)
   {
   case type_SelectPT:
      {
         const SelectPT &p=static_cast<const SelectPT&>(prim);
         if(p.get_pt_id()==get_object()->get_id())
         {
            switch(p.get_delegate().get_type())
            {
            case type_SetPTVisible:
               visible_check->blockSignals(true);
               visible_check->setChecked(get_object()->get_visible());
               visible_check->blockSignals(false);
               break;
            case type_SetPTLifeTime:
               life_time_widget->set_value(get_object()->get_life_time());
               break;
            case type_SetPTDensity:
               density_edit->blockSignals(true);
               density_edit->setText(QLocale::system().toString(get_object()->get_density()));
               density_edit->blockSignals(false);
               break;
            case type_SetPTGravitationEnabled:
               gravitation_check->blockSignals(true);
               gravitation_check->setChecked(get_object()->get_gravitation_enabled());
               gravitation_check->blockSignals(false);
               break;
            case type_SetPTFrictionEnabled:
               friction_check->blockSignals(true);
               friction_check->setChecked(get_object()->get_friction_enabled());
               friction_check->blockSignals(false);
               break;
            case type_SetPTShape:
               shape_combo->blockSignals(true);
               shape_combo->setCurrentIndex(shape_combo->findData(get_object()->get_shape()));
               shape_combo->blockSignals(false);
               break;
            case type_SetPTTextureFile:
               texture_edit->blockSignals(true);
               texture_edit->setText(get_object()->get_texture_file());
               texture_edit->blockSignals(false);
               break;
            case type_SetPTTileS:
               tile_s_spin->blockSignals(true);
               tile_s_spin->setValue(get_object()->get_tile_s());
               tile_s_spin->blockSignals(false);
               break;
            case type_SetPTTileT:
               tile_t_spin->blockSignals(true);
               tile_t_spin->setValue(get_object()->get_tile_t());
               tile_t_spin->blockSignals(false);
               break;
            case type_SetPTNumTiles:
               num_tiles_edit->blockSignals(true);
               num_tiles_edit->setText(QLocale::system().toString(get_object()->get_num_tiles()));
               num_tiles_edit->blockSignals(false);
               break;
            case type_SetPTTileSpeedMode:
               tile_speed_mode_combo->blockSignals(true);
               tile_speed_mode_combo->setCurrentIndex(tile_speed_mode_combo->findData(get_object()->get_tile_speed_mode()));
               tile_speed_mode_combo->blockSignals(false);
               break;
            }
         }
      }
      break;
   }
}
//
QWidget *PTGenericView::get_visible_widget() const
{
   return visible_check;
}
QWidget *PTGenericView::get_life_time_widget() const
{
   return life_time_widget;
}
QWidget *PTGenericView::get_density_widget() const
{
   return density_edit;
}
QWidget *PTGenericView::get_gravitation_enabled_widget() const
{
   return gravitation_check;
}
QWidget *PTGenericView::get_friction_enabled_widget() const
{
   return friction_check;
}
QWidget *PTGenericView::get_shape_widget() const
{
   return shape_combo;
}
QWidget *PTGenericView::get_texture_file_widget() const
{
   return texture_widget;
}
QWidget *PTGenericView::get_tile_s_widget() const
{
   return tile_s_spin;
}
QWidget *PTGenericView::get_tile_t_widget() const
{
   return tile_t_spin;
}
QWidget *PTGenericView::get_num_tiles_widget() const
{
   return num_tiles_edit;
}
QWidget *PTGenericView::get_tile_speed_mode_widget() const
{
   return tile_speed_mode_combo;
}
//
void PTGenericView::update_pt_texture_file(const QString &file_name)
{
   QScopedPointer<PrimitiveGroup> group(new PrimitiveGroup(get_document()));
   Primitives::SelectPT *prim;
   group->set_description(tr("change texture file of particle template '%1'","commands").arg(get_object()->get_name()));
   try
   {
      group->add_exec(prim=new Primitives::SelectPT(get_document(),get_object(),new Primitives::SetPTTextureFile(file_name)));
      group->finalize();
   }
   catch(UiError&)
   {
      return;
   }
   group.take();
}
void PTGenericView::block_edit_signals(bool p_block)
{
   visible_check->blockSignals(p_block);
   density_edit->blockSignals(p_block);
   gravitation_check->blockSignals(p_block);
   friction_check->blockSignals(p_block);
   shape_combo->blockSignals(p_block);
   texture_edit->blockSignals(p_block);
   tile_s_spin->blockSignals(p_block);
   tile_t_spin->blockSignals(p_block);
   num_tiles_edit->blockSignals(p_block);
   tile_speed_mode_combo->blockSignals(p_block);
}
